#include "x11_backend.h"

void *inputThread(void *vd)
{
    fd_set in_fds;
    Bool isMouseDown = False;
    struct timeval tv;
    struct virt_disp *vdp =(struct virt_disp *)vd;
    int x11_fd = ConnectionNumber(vdp->display);
    while (1)
    {
        FD_ZERO(&in_fds);
        FD_SET(x11_fd, &in_fds);
        tv.tv_usec = 0;
        tv.tv_sec = 1;

        int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
        if (num_ready_fds > 0)
        {
            pthread_mutex_lock(&vdp->mutex);
            while (XPending(vdp->display))
            {
                XNextEvent(vdp->display, &vdp->event); 
                switch (vdp->event.type)
                {
                case ButtonPress:
                    isMouseDown = True;
                    printf("press(%d,%d)\n", vdp->event.xbutton.x, vdp->event.xbutton.y);
                    break;
                case ButtonRelease:
                    isMouseDown = False;
                    printf("release(%d,%d)\n", vdp->event.xbutton.x, vdp->event.xbutton.y);
                    break;
                case MotionNotify:
                    if (isMouseDown)
                    {
                        printf("press(%d,%d)\n", vdp->event.xbutton.x, vdp->event.xbutton.y);
                    }
                    break;
                case KeyPress:
                    printf("%s\n", XKeysymToString(XLookupKeysym(&(vdp->event.xkey), 0)));
                    break;
                }
                fflush(stdout);
            }
            pthread_mutex_unlock(&vdp->mutex);
        }
    }
}

int virt_disp_flush_fb(struct virt_disp *vd, int refresh_interval)
{
    pthread_mutex_lock(&vd->mutex);
    XPutImage(vd->display, vd->win, vd->gc, vd->img, 0, 0, 0, 0, vd->width, vd->height);
    pthread_mutex_unlock(&vd->mutex);
    usleep(refresh_interval);
    return 0;
}


int virt_disp_init(struct virt_disp *vd)
{
    pthread_mutex_init(&vd->mutex, 0);

    vd->display = XOpenDisplay(NULL);
    int screen_num = DefaultScreen(vd->display);
    Window root = RootWindow(vd->display, screen_num);
    Visual *visual = DefaultVisual(vd->display, screen_num);
    int colorBits = DefaultDepth(vd->display, screen_num);
    vd->fbaddr = (char *)malloc(vd->width * vd->height * colorBits);

    vd->win = XCreateSimpleWindow(vd->display, root, 0, 0, vd->width, vd->height, 0, 0, 0);
    XSelectInput(vd->display, vd->win, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask);
    XMapWindow(vd->display, vd->win);

    pthread_t pid;
    pthread_create(&pid, NULL, inputThread, vd);

    vd->img = XCreateImage(vd->display, visual, colorBits, ZPixmap, 0, vd->fbaddr, vd->width, vd->height, 32, 0);

    vd->gc = DefaultGC(vd->display, screen_num);
    return 0;
}

int virt_disp_deinit(struct virt_disp *vd)
{
    XCloseDisplay(vd->display);
    free(vd->fbaddr);
    return 0;
}


